package com.atguigu.edu.realtime.common.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.lettuce.core.RedisClient;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.async.RedisAsyncCommands;
import org.apache.commons.lang3.StringUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * 操作Redis的工具类
 * 旁路缓存
 *      思路：先从缓存中获取要关联的维度，如果在缓存中找到了要关联的维度，直接将其作为返回值进行返回(缓存命中);
 *           如果在缓存中没有找到要关联的维度，发送请求到HBase中查询维度，并将查询的结果放到缓存中缓存起来，方便下次查询使用
 *      缓存产品选型：
 *          redis     性能也不错，维护性好    √
 *          状态      性能更好，维护性差
 *      关于redis的一些设置
 *          key:    维度表名:主键值   例如  dim_base_trademark:1
 *          type:   string
 *          expire: 1day 避免冷数据常驻内存，给内存带来压力
 *          注意: 如果维度数据发生了变化，需要将缓存的数据清除掉
 */
public class RedisUtil {
    private static JedisPool jedisPool;
    static {
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMinIdle(5);
        poolConfig.setMaxTotal(100);
        poolConfig.setMaxIdle(5);
        poolConfig.setBlockWhenExhausted(true);
        poolConfig.setMaxWaitMillis(2000L);
        poolConfig.setTestOnBorrow(true);
        jedisPool = new JedisPool(poolConfig,"hadoop102",6379,10000);
    }
    //获取Jedis
    public static Jedis getJedis() {
        System.out.println("~~~开启Jedis~~~");
        Jedis jedis = jedisPool.getResource();
        return jedis;
    }

    //关闭Jedis
    public static void closeJedis(Jedis jedis) {
        if (jedis != null) {
            System.out.println("~~~关闭Jedis~~~");
            jedis.close();
        }
    }

    public static void main(String[] args) {
        Jedis jedis = getJedis();
        System.out.println(jedis.ping());
    }

    //从Redis中获取维度数据的方法
    public static JSONObject  readDim(Jedis jedis,String tableName,String id){
        String key = getKey(tableName,id);
        String dimJsonStr = jedis.get(key);
        if(StringUtils.isNotEmpty(dimJsonStr)){
            JSONObject jsonObj = JSON.parseObject(dimJsonStr);
            return jsonObj;
        }
        return null;
    }


    private static String getKey(String tableName, String id) {
        return tableName + ":" + id;
    }
    //向Redis中放维度数据的方法
    public static void writeDim(Jedis jedis, String tableName, String id, JSONObject jsonObj){
        String key = getKey(tableName, id);
        jedis.setex(key,24*3600, jsonObj.toJSONString());
    }




    //TODO 获取支持异步操作的Redis客户端
    public static StatefulRedisConnection<String,String> getAsyncRedisConnection(){
        RedisClient redisClient = RedisClient.create("redis://hadoop102:6379/0");
        System.out.println("~~~获取异步操作Redis的连接对象~~~");
        StatefulRedisConnection<String, String> redisConnection = redisClient.connect();
        return redisConnection;
    }
    //TODO 关闭支持异步操作的Redis客户端
    public static void closeAsyncRedisConnection(StatefulRedisConnection<String,String> redisConnection){
        if(redisConnection!=null&& redisConnection.isOpen()){
            System.out.println("~~~关闭异步操作Redis的连接对象~~~");
            redisConnection.close();
        }
    }

    //以异步的方式从redis中获取维度数据的方法
    public static JSONObject readDimAsync(StatefulRedisConnection<String ,String> redisConnection,String tableName,String id){
        RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
        String key = getKey(tableName, id);
        try {
            //如果获取到了维度数据,且维度数据不为空，返回维度数据对象，否则返回null值
            String dimJsonStr = asyncCommands.get(key).get();
            if(StringUtils.isNotEmpty(dimJsonStr)){
                JSONObject dimJsonObj = JSON.parseObject(dimJsonStr);
                return dimJsonObj;
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return null;
    }

    //以异步的方式向redis中放维度数据的方法
    public static void writeDimAsync(StatefulRedisConnection<String,String> redisConnection,String tableName,String id ,JSONObject jsonObject){
        String key = getKey(tableName, id);
        //从链接中获取命令行对象
        RedisAsyncCommands<String, String> asyncCommands = redisConnection.async();
        asyncCommands.setex(key,24*3600, jsonObject.toJSONString());
    }

}